package top.cardone.template.support.impl;

import com.google.common.collect.Maps;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import top.cardone.core.CodeException;
import top.cardone.template.support.TemplateSupport;

import java.io.File;
import java.util.Map;
import java.util.Objects;

/**
 * @author yao hai tao
 */
@lombok.extern.log4j.Log4j2
public class TemplateSupportImpl implements TemplateSupport {
	/**
	 * 消息格式化映射
	 */
	@lombok.Getter
	@lombok.Setter
	private Map<String, Configuration> configurationMap = Maps.newConcurrentMap();
	/**
	 * freemarker.template.Configuratio
	 */
	@lombok.Getter
	@lombok.Setter
	private String defaultConfigurationKey = "configuration1";
	/**
	 * 显示model
	 */
	@lombok.Getter
	@lombok.Setter
	private Boolean showModel = true;

	/**
	 * 显示解析模板后字符串
	 */
	@lombok.Getter
	@lombok.Setter
	private Boolean showProcessTemplateIntoString = true;

	/**
	 * 显示模板字符串
	 */
	@lombok.Getter
	@lombok.Setter
	private Boolean showTemplateString = false;

	/**
	 * 模板映射
	 */
	private Map<String, Template> templateMap = Maps.newConcurrentMap();

	@Override
	public String process(final String filePath, final Object model) {
		return this.process(this.defaultConfigurationKey, filePath, model);
	}

	@Override
	public String toString(String configurationKey, String filePath) {
		if (CollectionUtils.isEmpty(configurationMap) || !configurationMap.containsKey(configurationKey)) {
			return StringUtils.EMPTY;
		}

		Configuration configuration = configurationMap.get(configurationKey);

		try {
			Object object = configuration.getTemplateLoader().findTemplateSource(filePath);

			if (object == null) {
				throw new CodeException("00000021", "文件不存在");
			}

			File file = new File(object.toString());

			if (!file.exists()) {
				throw new CodeException("00000021", "文件不存在");
			}

			return FileUtils.readFileToString(file);
		} catch (java.io.IOException e) {
			throw new CodeException("00000000", e);
		}
	}

	@Override
	public String toString(String filePath) {
		return this.toString(this.defaultConfigurationKey, filePath);
	}

	@Override
	public String process(String configurationKey, String filePath, Object model) {
		if (CollectionUtils.isEmpty(configurationMap) || !configurationMap.containsKey(configurationKey)) {
			return StringUtils.EMPTY;
		}

		Configuration configuration = configurationMap.get(configurationKey);

		try {
			final Template template = configuration.getTemplate(filePath);

			if (BooleanUtils.isTrue(this.showTemplateString)) {
				log.warn(template.toString());
			}

			String str;

			try (java.io.StringWriter writer = new java.io.StringWriter()) {
				template.process(model, writer);

				str = writer.toString();
			}

			if (BooleanUtils.isTrue(this.showProcessTemplateIntoString)) {
				log.warn(str);
			}

			if (BooleanUtils.isTrue(this.showModel)) {
				log.warn(Objects.toString(model));
			}

			return StringUtils.defaultIfBlank(str, StringUtils.EMPTY);
		} catch (freemarker.template.TemplateException | java.io.IOException e) {
			throw new CodeException("00000000", e);
		}
	}

	@Override
	public String processString(final String templateString, final Object model) {
		return processString(this.defaultConfigurationKey, templateString, model);
	}

	@Override
	public String processString(String configurationKey, String templateString, Object model) {
		if (CollectionUtils.isEmpty(configurationMap) || !configurationMap.containsKey(configurationKey)) {
			return StringUtils.EMPTY;
		}

		if (StringUtils.isBlank(templateString)) {
			return StringUtils.EMPTY;
		}

		if (BooleanUtils.isTrue(this.showTemplateString)) {
			log.warn(templateString);
		}

		try (java.io.StringWriter writer = new java.io.StringWriter()) {
			final String name = DigestUtils.md5Hex(templateString);

			Template template = templateMap.get(name);

			if (template == null) {
				try (java.io.Reader reader = new java.io.StringReader(templateString)) {
					Configuration configuration = configurationMap.get(configurationKey);

					template = new Template(name, reader, configuration);

					templateMap.put(name, template);
				}
			}

			template.process(model, writer);

			String str = writer.toString();

			if (BooleanUtils.isTrue(this.showProcessTemplateIntoString)) {
				log.warn(str);
			}

			if (BooleanUtils.isTrue(this.showModel)) {
				log.warn(Objects.toString(model));
			}

			return str;
		} catch (Exception e) {
			throw new CodeException("00000000", e);
		}
	}
}